#include "user_global.h"
#include "user_device.h"
#include "device_spi.h"
#include "spi.h"


uchar spi_sendtimeout = 100;                    // 串口发送超时时间,ms

uchar  spi_rx_len = 0;                          // 已接收/或要发送长度
ushort  spi_rx_buf[SPI_BUF_SIZE];               // spi发送/接收缓冲区
ulong  spi_timestamp;                           // 最后接收时间
ushort *spi_tx_ptr;                             // 发送指针
bit spi_rx_pending = 0;                         // spi正在接收标志
bit spi_tx_pending = 0;                         // spi正在发送标志
uchar  spi_tx_len = 0;                          // uart1要发送长度
ushort  spi_tx_buf[SPI_BUF_SIZE];               // uart1发送缓冲区
uchar spi_result;                               // uart1通讯结果, 见UART1_RESULT_xxx

CS_GPORT spics_gport[DRV_COUNT] =
{
    {SPICS1_GPIO_Port, SPICS1_Pin},
    {SPICS2_GPIO_Port, SPICS2_Pin},
    {SPICS3_GPIO_Port, SPICS3_Pin},
    {SPICS4_GPIO_Port, SPICS4_Pin}
};

REG_DRVCTRL reg_drvctrl[DRV_COUNT] =
{
    {
        1,                   // uchar enbl   : 1;
        0,                   // uchar rdir   : 1;
        0,                   // uchar rstep  : 1;
        0x04,                // uchar mode   : 4;
        0,                   // uchar extall : 1;
        0,                   // uchar isgain : 2;
        0,                   // uchar dtime  : 2;
        0x00,                // uchar addr : 3;
        0,                   // uchar readwrite : 1;
    },
    {
        1,                   // uchar enbl   : 1;
        0,                   // uchar rdir   : 1;
        0,                   // uchar rstep  : 1;
        0x04,                // uchar mode   : 4;
        0,                   // uchar extall : 1;
        0,                   // uchar isgain : 2;
        0,                   // uchar dtime  : 2;
        0x00,                // uchar addr : 3;
        0,                   // uchar readwrite : 1;
    },
    {
        1,                   // uchar enbl   : 1;
        0,                   // uchar rdir   : 1;
        0,                   // uchar rstep  : 1;
        0x04,                // uchar mode   : 4;
        0,                   // uchar extall : 1;
        0,                   // uchar isgain : 2;
        0,                   // uchar dtime  : 2;
        0x00,                // uchar addr : 3;
        0,                   // uchar readwrite : 1;
    },
    {
        1,                   // uchar enbl   : 1;
        0,                   // uchar rdir   : 1;
        0,                   // uchar rstep  : 1;
        0x04,                // uchar mode   : 4;
        0,                   // uchar extall : 1;
        0,                   // uchar isgain : 2;
        0,                   // uchar dtime  : 2;
        0x00,                // uchar addr : 3;
        0,                   // uchar readwrite : 1;
    },
};

REG_TORQUE reg_torque[4] =
{
    {
        0,                   // uchar torque   : 8;
        0,                   // uchar smplth   : 3;
        0,                   // uchar reserverd : 1;
        0x01,                // uchar addr : 3;
        0,                   // uchar readwrite : 1;
    },
    {
        0,                   // uchar torque   : 8;
        0,                   // uchar smplth   : 3;
        0,                   // uchar reserverd : 1;
        0x01,                // uchar addr : 3;
        0,                   // uchar readwrite : 1;
    },
    {
        0,                   // uchar torque   : 8;
        0,                   // uchar smplth   : 3;
        0,                   // uchar reserverd : 1;
        0x01,                // uchar addr : 3;
        0,                   // uchar readwrite : 1;
    },
   {
        0,                   // uchar torque   : 8;
        0,                   // uchar smplth   : 3;
        0,                   // uchar reserverd : 1;
        0x01,                // uchar addr : 3;
        0,                   // uchar readwrite : 1;
    },
};

REG_DECAY reg_decay[DRV_COUNT] =
{
    {
        0x10,                // tdecay   : 8;
        SLOW_DECAY_AUTO_MIXED,                // decmode  : 3;
        0,                   // reserverd: 1;
        0x04,                // uchar addr : 3;
        0,                   // uchar readwrite : 1;
    },
    {
        0x10,                // tdecay   : 8;
        SLOW_DECAY_AUTO_MIXED,                // decmode  : 3;
        0,                   // reserverd: 1;
        0x04,                // uchar addr : 3;
        0,                   // uchar readwrite : 1;
    },
    {
        0x10,                // tdecay   : 8;
        SLOW_DECAY_AUTO_MIXED,                // decmode  : 3;
        0,                   // reserverd: 1;
        0x04,                // uchar addr : 3;
        0,                   // uchar readwrite : 1;
    },
    {
        0x10,                // tdecay   : 8;
        MIXED_DECAY,                // decmode  : 3;
        0,                   // reserverd: 1;
        0x04,                // uchar addr : 3;
        0,                   // uchar readwrite : 1;
    },
};

//将多字节数大小端互换
ulong from_little_endian_24(ulong n)
{
    return  ((n << 16)  & 0xFF0000) |
            ((n >> 16 ) & 0x0000FF)|
            (n          & 0x00FF00);
}

void Spi_Slave_Wait(uchar ch, uchar act)
{
    ulong stamp;
    if(act == SPI_READ)
    {
        TIMER_START(stamp);
        while(RESET == spi_i2s_flag_get(SPI2, SPI_FLAG_RBNE))
        {
            if(TIMER_OUT(stamp, 50000))
                break;
        }
    }
    else if(act == SPI_WRITE)
    {
        TIMER_START(stamp);
        while(RESET == spi_i2s_flag_get(SPI2, SPI_FLAG_TBE))
        {
            if(TIMER_OUT(stamp, 50000))
                break;
             Main_Loop();
        }
    }

}

bit Spi_WriteRead(uchar ch, ushort*write, ushort *read, uchar size)
{
    bit result = 1;
    ushort write_data, read_data;
    uchar i;
    for(i = 0; i < size; ++i)
    {
        IO_SPI_SELECT(ch);
        Spi_Slave_Wait(ch, SPI_WRITE);
        write[i] &=~SPI_WRITE_MASK;
        spi_i2s_data_transmit(SPI2, write[i]);
        Spi_Slave_Wait(ch, SPI_READ);
        spi_i2s_data_receive(SPI2);
        write_data = (write[i] & (SPI_DATA_MASK));
        IO_SPI_SELECT_NONE();

        Delay_Tick_Loop(5000);
        IO_SPI_SELECT(ch);
        Spi_Slave_Wait(ch, SPI_WRITE);
        write[i] |= SPI_READ_MASK;
        spi_i2s_data_transmit(SPI2, write[i]);
        Spi_Slave_Wait(ch, SPI_READ);
        read[i] = spi_i2s_data_receive(SPI2);
        read_data = (read[i] & (SPI_DATA_MASK));
        IO_SPI_SELECT_NONE();
        Delay_Tick_Loop(2000);

        if(read_data != write_data)
             result = 0;
    }
    return result;
}

void SPI_Send_Data(void)
{
    /* enable TBE interrupt */
    if(spi_tx_len)
    {
        spi_i2s_data_transmit(SPI2, *spi_tx_ptr++);
        --spi_tx_len;
    }
    spi_i2s_interrupt_enable(SPI2, SPI_I2S_INT_TBE);
}

bit SPI_Send_Message(void)
{
    ushort interval;

    // 距接收经过的时间
    interval = timer_counter_read(TIMER5) - spi_timestamp;

    // 如果发送距接收时间不足2ms, 等待
    if (interval < TWO_MS)
        Delay_Tick(TWO_MS - interval);

    spi_tx_pending = 1;
    spi_tx_ptr = spi_tx_buf;
    SPI_Send_Data();

    return 1;
}

// 读取数据帧
void SPI_Read()
{
     // 未完成接收
    if (!TIMER_OUT(spi_timestamp, 10000))
        return;

    // 10ms超时
    if (spi_rx_len == 0)
        spi_result = SPI_RESULT_TIMEOUT;
    else
    {
        spi_result = SPI_RESULT_OK;
    }

    spi_rx_pending = 0;
}

// uart1发送
void SPI_Send()
{

    spi_rx_pending = 0;
    spi_tx_pending = 1;
    spi_rx_len = 0;
    spi_tx_ptr = spi_tx_buf;

    Delay_us(400);

    spi_i2s_interrupt_enable(SPI2, SPI_I2S_INT_TBE);

    // 等待发送完成
    while(spi_tx_pending)
        Update_WatchDog();

    // 设置10ms超时
    TIMER_START(spi_timestamp);
    spi_tx_pending = 0;
    spi_rx_pending = 1;
}

bit SPI_Exchange_Message(void)
{
    ushort retry_times = 5;

    do
    {
        SPI_Send();

        // 等待发送完成
        while(spi_tx_pending)
            Main_Loop();

        // 等待接收完成
        while(spi_rx_pending)
        {
            Main_Loop();
            SPI_Read();
        }

        // 从主循环恢复, 接收完成
        if (spi_result == SPI_RESULT_OK)
        {
            return 1;
        }
    }
    while(--retry_times);

    return 0;
}

bit SPI_Read_Word(uchar addr)
{
    ushort dr = (ushort)(SPI_READ << 15) | (ushort)(addr << 14);

    SPI_START();
    SPI_APPEND(ushort, dr);
    SPI_END();

    return SPI_Exchange_Message();
}

bit SPI_Write_Word(uchar addr, ushort value)
{
    ushort dr = (ushort)(SPI_WRITE << 15) | (ushort)(addr << 14) | (value & 0xFFF);
    SPI_START();
    SPI_APPEND(ushort, dr);
    SPI_END();

    return SPI_Exchange_Message();
}

void Drv_Init(uchar role)
{
    ushort read[1] = {0x0001};
    float buf[DRV_COUNT] = {S1_EXPECTED_WORK_CURRENT,S2_EXPECTED_WORK_CURRENT,S3_EXPECTED_WORK_CURRENT,S4_EXPECTED_WORK_CURRENT};

    IO_SPI_SELECT(role);

    reg_torque[role].torque = TOUQUE_VALUE(role, buf[role]);

    Spi_WriteRead(role, (ushort*)&reg_drvctrl[role], read, 1);
    Spi_WriteRead(role, (ushort*)&reg_torque[role], read, 1);

    IO_SPI_SELECT_NONE();
}

void Drv_Work_Full(uchar role)
{
    ushort read[1] = {0x0001};
    float buf[DRV_COUNT] = {S1_EXPECTED_WORK_CURRENT,S2_EXPECTED_WORK_CURRENT,S3_EXPECTED_WORK_CURRENT,S4_EXPECTED_WORK_CURRENT};

    if(role >= DRV_COUNT)
        return;
    IO_SPI_SELECT(role);

    reg_drvctrl[role].enbl = 1;
    reg_torque[role].torque = TOUQUE_VALUE(role, buf[role]);

    Spi_WriteRead(role, (ushort*)&reg_drvctrl[role], read, 1);
    Spi_WriteRead(role, (ushort*)&reg_torque[role], read, 1);

    IO_SPI_SELECT_NONE();
}

void Drv_Work_Lock(uchar role)
{
    ushort read[1] = {0x0001};
    float buf[DRV_COUNT] = {S1_EXPECTED_WORK_CURRENT,S2_EXPECTED_WORK_CURRENT,S3_EXPECTED_WORK_CURRENT,S4_EXPECTED_LOCK_CURRENT};

    if(role >= DRV_COUNT)
        return;

    IO_SPI_SELECT(role);

    reg_drvctrl[role].enbl = 1;
    reg_torque[role].torque = TOUQUE_VALUE(role, buf[role]);
    
    Spi_WriteRead(role, (ushort*)&reg_drvctrl[role], read, 1);
    Spi_WriteRead(role, (ushort*)&reg_torque[role], read, 1);

    IO_SPI_SELECT_NONE();
}

void Drv_Disable(uchar role)
{
    ushort read[1] = {0x0001};
    float buf[DRV_COUNT] = {S1_EXPECTED_LOCK_CURRENT,S2_EXPECTED_LOCK_CURRENT,S3_EXPECTED_LOCK_CURRENT,S4_EXPECTED_LOCK_CURRENT};

    if(role >= DRV_COUNT)
        return;
    IO_SPI_SELECT(role);

    reg_drvctrl[role].enbl = 0;
    reg_torque[role].torque = TOUQUE_VALUE(role, buf[role]);

    Spi_WriteRead(role, (ushort*)&reg_drvctrl[role], read, 1);
    Spi_WriteRead(role, (ushort*)&reg_torque[role], read, 1);

    IO_SPI_SELECT_NONE();
}

void Drv_Set_Decay(uchar role)
{
    ushort read[1] = {0x0001};

    if(role >= DRV_COUNT)
        return;
    IO_SPI_SELECT(role);

    Spi_WriteRead(role, (ushort*)&reg_decay[role], read, 1);

    IO_SPI_SELECT_NONE();
}
